/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1/commercial
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may use this file in compliance with the License.
 * Alternatively, if you can't copy with the License, namely if you do not
 * want to provide source code of your modifications to this file, you may
 * negotiate a commercial licence with the initial developer.
 * You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID.
 *
 * The Initial Developer of the Original Code is
 * Brano Kemen.
 * Portions created by the Initial Developer are Copyright (C) 2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Brano Kemen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "httpstreamapache.h"
#include <coid/server/tunnelmgr/client/tunnelmgr_client.h>
#include "conf.h"

///Per thread data
struct ThrData
{
    httpstreamapache net;
    TunnelMgr_client tun;
};

int coid_run( int& port, const char* libserver, const char* conf );
void coid_stop();


extern "C" {

////////////////////////////////////////////////////////////////////////////////
void* coid_thr_data_create()
{
    return new ThrData;
}

////////////////////////////////////////////////////////////////////////////////
void coid_thr_data_destroy( void* p )
{
    delete (ThrData*)p;
}

int coid_init( CoidConfig* conf, apr_pool_t *p )
{
    if( conf->workdir )
    {
        char* str = (char*)apr_palloc( p, 16 );
        ::strcpy( str, "localhost:" );
        ::itoa( (ushort)conf->port, str+10, 10 );
        conf->rempath = str;

        return coid_run( conf->port, conf->libserver, conf->workdir );
    }
    else
        return 0;
}

////////////////////////////////////////////////////////////////////////////////
int coid_reconnect(CoidConfig* conf, ThrData &tr)
{
	coid::charstr addr;

	if (conf->rempath) {
		addr += conf->rempath;
		addr += ':';
		addr += conf->port;
	}
	static const char * const lpath = "localhost";

    const opcd e = tr.tun.connect(conf->rempath ? addr.c_str() : lpath);
    
	if (e) return 504;

	return 0;
}

////////////////////////////////////////////////////////////////////////////////
int coid_process_req( request_rec* rec, CoidConfig* conf, void* p, const int mode )
{
    ThrData& tr = *(ThrData*)p;

    rec->no_cache = 1;
    tr.net.set(rec);

    if( !tr.tun.is_connected() ) {
		int e=coid_reconnect(conf,tr);
		if( e ) return e;
	}

	int err;
	coid::dynarray<uchar> buf;

	if (!(err = ap_setup_client_block(rec, REQUEST_CHUNKED_ERROR)) &&
		ap_should_client_block(rec)) {
		apr_uint32_t read = 0;
		int res;

		buf.resize(4096);

		while (((res = ap_get_client_block(
			rec, (char*)buf.ptr() + read, buf.size() - read)) > 0)) {
				read += res;
				if (read == buf.size() && res != 0)
					buf.resize(buf.size() + 4096);
		}

		if (res != -1)
			buf .resize(read);
		else
			return 502;
	}

	if (!err) {
		if (mode == 1) {
			netAddress addr;
			uint64 ssid = tr.net.get_session_id();

			token service = rec->uri;
			charstr soapgw=conf->soapgw;
			soapgw+='/';
			
			service = service.get_after_substring(substring(soapgw));

			if( tr.tun.process_remote_soap_call(buf, charstr(service), addr, ssid) ) {
				if( coid_reconnect(conf,tr) )
					return 502;
				if( tr.tun.process_remote_soap_call(buf, charstr(service), addr, ssid) )
					return 502;
			} else
				return 502;

			//tr.net.set_session_id(ssid);
			tr.net.set_content_type("text/xml");
			//ap_set_content_type(rec, ct.c_str());
			ap_send_http_header(rec);
			ap_rwrite(buf.ptr(), static_cast<int>(buf.size()), rec);
		} else {
			uint64 ssid = tr.net.get_session_id();
			coid::charstr ct;
			netAddress addr;
			if( !tr.tun.process_remote_call(buf, rec->args + 5, addr, ssid, ct) ) {
				tr.net.set_session_id(ssid);
				tr.net.set_content_type(ct.c_str());

				ap_set_content_type(rec, ct.c_str());
				ap_send_http_header(rec);
				ap_rwrite(buf.ptr(), static_cast<int>(buf.size()), rec);
			} else 
				return 502;
		}
	}

	return err ? 502 : OK;
}

} //extern "C"

